/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/spi.h"
#include "pico.h"
#include "hardware/irq.h"

#define ADS1292_ID 0x53
#define ADS1292R_ID 0x73
#define LED_PIN PICO_DEFAULT_LED_PIN
#define DRDY_PIN 19
#define AVDD_EN_PIN 21
#define ADS1292_CS_PIN 13
#define ADS1292_MISO_PIN 12
#define ADS1292_MOSI_PIN 11
#define ADS1292_CLK_PIN 10

static char event_str[128];
static bool ads1292_data_ready = false;
uint32_t irq_count = 0;
uint8_t ret = false;
bool leadoff_flag = false;
bool led_on = false;

#pragma pack()
typedef struct
{
    uint8_t status;
    int32_t channel1;
    int32_t channel2;
} ADS1292_RESULT;
#pragma pack()

ADS1292_RESULT ads1292Result;
int32_t temp_buf[125] = {0};
typedef enum
{
    ADS1292_COMMAND_WAKEUP = 0x02,
    ADS1292_COMMAND_STANDBY = 0x04,
    ADS1292_COMMAND_RESET = 0x06,
    ADS1292_COMMAND_START = 0x08,
    ADS1292_COMMAND_STOP = 0x0A,
    ADS1292_COMMAND_OFFSETCAL = 0x1A,
    ADS1292_COMMAND_RDATAC = 0x10,
    ADS1292_COMMAND_SDATAC = 0x11,
    ADS1292_COMMAND_RDATA = 0x12,
    ADS1292_COMMAND_RREG = 0x20,
    ADS1292_COMMAND_WREG = 0x40,
} ADS1292_COMMAND;
typedef enum
{
    ADS1292_REGISTER_ID = 0x00,
    ADS1292_REGISTER_CONFIG1 = 0x01,
    ADS1292_REGISTER_CONFIG2 = 0x02,
    ADS1292_REGISTER_LOFF = 0x03,
    ADS1292_REGISTER_CH1SET = 0x04,
    ADS1292_REGISTER_CH2SET = 0x05,
    ADS1292_REGISTER_RLD_SENS = 0x06,
    ADS1292_REGISTER_LOFF_SENS = 0x07,
    ADS1292_REGISTER_LOFF_STAT = 0x08,
    ADS1292_REGISTER_RESP1 = 0x09,
    ADS1292_REGISTER_RESP2 = 0x0A,
    ADS1292_REGISTER_GPIO = 0x0B,
    ADS1292_REGISTER_TOTAL,

    ADS1292_REGISTER_TERMINATE = 0xFF,
} ADS1292_REGISTER;
typedef struct
{
    ADS1292_REGISTER reg;
    uint8_t val;
} ADS1292_SETTING;
static ADS1292_SETTING ads1292RegSetting[] =
    {
        {ADS1292_REGISTER_CONFIG1, 0x00}, /* [2:0] 000-125Hz,001-250Hz,010-500Hz(default) */
        {ADS1292_REGISTER_CONFIG2, 0xE0},
        {ADS1292_REGISTER_LOFF, 0x14},
        {ADS1292_REGISTER_CH1SET, 0x40},
        {ADS1292_REGISTER_CH2SET, 0x40},
        {ADS1292_REGISTER_RLD_SENS, 0xB3},
        {ADS1292_REGISTER_LOFF_SENS, 0x0F},
        {ADS1292_REGISTER_RESP1, 0x02},
        {ADS1292_REGISTER_RESP2, 0x03},
        //{ADS1292_REGISTER_GPIO,			0x0B},
        {ADS1292_REGISTER_TERMINATE, 0x00}};

#define ADS1292_REG_ADDR_MASK (0x1F)
#define ADS1292_REG_NUM_MASK (0x1F)

/* 24bit status + 24bit channel-I data + 24bit channel-II data = 72bit data=9Bytes
    if not use channel-II data, set 6(48bit)
*/
#define ADS1292_RESULT_BYTES (9)
/* 转换24bit有符号数到32bit */
#define CAST24to32(i24) (((i24) & 0x800000) ? ((i24) | 0xFF800000) : (i24))
void gpio_event_string(char *buf, uint32_t events);

static void GPIO_init()
{
    printf("GPIO_init\n");
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);
    gpio_put(LED_PIN, 1);

    gpio_init(DRDY_PIN);
    gpio_set_dir(DRDY_PIN, GPIO_IN);
    gpio_pull_up(DRDY_PIN);

    gpio_init(AVDD_EN_PIN);
    gpio_set_dir(AVDD_EN_PIN, GPIO_OUT);
    gpio_pull_up(AVDD_EN_PIN);
    gpio_put(AVDD_EN_PIN, 1);

    gpio_init(ADS1292_CS_PIN);
    gpio_set_dir(ADS1292_CS_PIN, GPIO_OUT);
    gpio_put(ADS1292_CS_PIN, 1);

    // gpio_init(ADS1292_MISO_PIN);
    // gpio_pull_up(ADS1292_MISO_PIN);

    // gpio_init(ADS1292_MOSI_PIN);
    // gpio_pull_up(ADS1292_MOSI_PIN);

    // gpio_init(ADS1292_CLK_PIN);
    // gpio_pull_up(ADS1292_CLK_PIN);
}
static void read_registers(uint8_t *reg, uint8_t *buf, uint16_t len)
{
    // For this particular device, we send the device the register we want to read
    // first, then subsequently read from the device. The register is auto incrementing
    // so we don't need to keep sending the register we want, just the first.

    gpio_put(ADS1292_CS_PIN, 0);
    // sleep_ms(10);
    spi_write_read_blocking(spi1, reg, buf, len);
    sleep_us(10);
    gpio_put(ADS1292_CS_PIN, 1);
}
static int ADS1292_RegisterWrite(int reg, int num, uint8_t *buf)
{
    uint8_t txBuf[ADS1292_REGISTER_TOTAL + 2];
    uint8_t rxBuf[ADS1292_REGISTER_TOTAL + 2];

    txBuf[0] = ADS1292_COMMAND_WREG | (reg & ADS1292_REG_ADDR_MASK);
    txBuf[1] = (num - 1) & ADS1292_REG_NUM_MASK;
    for (int i = 0; i < num; i++)
    {
        txBuf[i + 2] = buf[i];
    }
    read_registers(txBuf, rxBuf, num + 2);
    return 0;
}

static int ADS1292_RegisterRead(int reg, int num, uint8_t *buf)
{
    uint8_t txBuf[ADS1292_REGISTER_TOTAL + 2] = {0};
    uint8_t rxBuf[ADS1292_REGISTER_TOTAL + 2] = {0};

    txBuf[0] = ADS1292_COMMAND_RREG | (reg & ADS1292_REG_ADDR_MASK);
    txBuf[1] = (num - 1) & ADS1292_REG_NUM_MASK;

    printf("Reg Write:%x %x \n", txBuf[0], txBuf[1]);

    read_registers(txBuf, rxBuf, num + 2);
    for (int i = 0; i < num; i++)
    {
        buf[i] = rxBuf[i + 2];
        printf("Reg Read: %x\n", rxBuf[i + 2]);
    }
    return 0;
}

static void ADS1292_CommandSend(ADS1292_COMMAND command)
{
    uint8_t buf;

    buf = command;
    read_registers(&buf, NULL, 1);
}

static void ADS1292_Wakeup(void)
{
    ADS1292_CommandSend(ADS1292_COMMAND_WAKEUP);
}

static void ADS1292_Reset(void)
{
    ADS1292_CommandSend(ADS1292_COMMAND_RESET);
}

static void blink_LED(bool value)
{
    gpio_put(LED_PIN, value);
}

static void ADS1292_readID()
{
    uint8_t id[1] = {0};
    ADS1292_RegisterRead(ADS1292_REGISTER_ID, 1, id);
    printf("Chip ID is 0x%x\n", id[0]);
}

static void ADS1292_Stop(void)
{
    ADS1292_CommandSend(ADS1292_COMMAND_SDATAC);
}

void ADS1292_ResetAll()
{
    ADS1292_Wakeup();
    ADS1292_Reset();
    sleep_ms(1000);
    ADS1292_Stop();
    sleep_ms(100);
}

/*********************************************************************
 * @fn		        ADS1292_RegisterConfig
 *
 * @brief		    config ads1292 register data
 *
 * @param           reg - register
 * @param           num - data number
 * @param           buf - config buffer
 *
 * @return          int - 0 is sucess, others are fail.
 **/
static int ADS1292_RegisterConfig(int reg, int num, uint8_t *buf)
{
    uint8_t temp[ADS1292_REGISTER_TOTAL];

    if (ADS1292_RegisterWrite(reg, num, buf) == 0)
    {
        sleep_us(50);
        if (ADS1292_RegisterRead(reg, num, temp) == 0)
        {
            if (ADS1292_REGISTER_GPIO == reg)
            {
                if ((buf[0] & 0x0C) != (temp[0] & 0x0C))
                {
                    return -1;
                }
                if (0x00 == (buf[0] & 0x04))
                {
                    if ((buf[0] & 0x01) != (temp[0] & 0x01))
                    {
                        return -1;
                    }
                }
                if (0x00 == (buf[0] & 0x08))
                {
                    if ((buf[0] & 0x02) != (temp[0] & 0x02))
                    {
                        return -1;
                    }
                }
                return 0;
            }
            else
            {
                if (memcmp(buf, temp, num) == 0)
                {
                    return 0;
                }
            }
        }
    }
    return -1;
}

/*********************************************************************
 * @fn		        ADS1292_ContinueStart
 *
 * @brief		    Enable Read Data Continuous mode.
 *
 * @return          int - 0 is sucess, others are fail.
 **/
int ADS1292_ContinueStart(void)
{
    ADS1292_CommandSend(ADS1292_COMMAND_RDATAC);

    return 0;
}

/*********************************************************************
 * @fn		        ADS1292_ConvertStart
 *
 * @brief		    start convert
 *
 * @return          int - 0 is sucess, others are fail.
 **/
int ADS1292_ConvertStart(void)
{
    ADS1292_CommandSend(ADS1292_COMMAND_START);

    return 0;
}

uint8_t ADS1292_Init(void)
{
    uint8_t i = 0;
    uint8_t ui8ADS1292ChipId = 0;
    ADS1292_RegisterRead(ADS1292_REGISTER_ID, 1, &ui8ADS1292ChipId);

    if (ui8ADS1292ChipId != ADS1292R_ID)
    {
        return 3;
    }

    i = 0;

    while (ADS1292_REGISTER_TERMINATE != ads1292RegSetting[i].reg)
    {
        if (0 != ADS1292_RegisterConfig(ads1292RegSetting[i].reg, 1, &ads1292RegSetting[i].val))
        {
            return (4 + i);
        }
        i++;
    }
    if (0 != ADS1292_ContinueStart())
    {
        return (i + 4);
    }
    if (0 != ADS1292_ConvertStart())
    {
        return (i + 5);
    }

    return 0;
}

/*********************************************************************
 * @fn		        ADS1292_ResultRead
 *
 * @brief		    read ads1292 data
 *
 * @param           result - 9Bytes data
 *
 * @return          int - 0 is sucess, others are fail.
 **/
static int ADS1292_ResultRead(ADS1292_RESULT *result)
{
    uint8_t txBuf[ADS1292_RESULT_BYTES] = {0};
    uint8_t rxBuf[ADS1292_RESULT_BYTES] = {0};

    read_registers(txBuf, rxBuf, ADS1292_RESULT_BYTES);

    {
        if ((rxBuf[0] & 0xF0) == 0xC0)
        {
            result->status = ((rxBuf[0] & 0x0F) << 1) | ((rxBuf[1] & 0x80) >> 7);
            result->channel1 = CAST24to32((rxBuf[3] << 16) | (rxBuf[4] << 8) | (rxBuf[5] << 0));
            result->channel2 = CAST24to32((rxBuf[6] << 16) | (rxBuf[7] << 8) | (rxBuf[8] << 0));
            return 0;
        }
    }
    return -1;
}
static void gpio_callback(uint gpio, uint32_t events)
{
    // Put the GPIO event(s) that just happened into event_str
    // so we can print it
    gpio_event_string(event_str, events);
    if (ads1292_data_ready == false)
    {
        ads1292_data_ready = true;
    }
    irq_count++;
}

int main()
{
    uint8_t temp = 0;
    uint8_t res = 1;
    stdio_init_all();
    GPIO_init();
    gpio_put(AVDD_EN_PIN, 1);

    spi_init(spi1, 1000 * 1000);
    gpio_set_function(ADS1292_MISO_PIN, GPIO_FUNC_SPI);
    gpio_set_function(ADS1292_CLK_PIN, GPIO_FUNC_SPI);
    gpio_set_function(ADS1292_MOSI_PIN, GPIO_FUNC_SPI);
    printf("Task start\n");

    gpio_set_irq_enabled_with_callback(DRDY_PIN, GPIO_IRQ_EDGE_FALL, true, gpio_callback);

    // while (res)
    {
        temp++;
        ADS1292_ResetAll();
        res = ADS1292_Init();
        printf("Ads1292 init:%d\n", res);
    }
    // while (1)
    // {
    //     printf("count:%d\n", temp);
    //     printf("Ads1292 init:%d\n", res);
    //     sleep_ms(1000);
    // }
    // Wait forever
    while (1)
    {
        if (ads1292_data_ready)
        {
            ret = ADS1292_ResultRead(&ads1292Result);
            temp_buf[irq_count] = ads1292Result.channel1;
            ads1292_data_ready = false;
        }
        else
        {
            sleep_us(100);
        }
        if (irq_count >= 125)
        {
            printf("%d\n", temp_buf[0]);
            irq_count = 0;
            for (uint8_t j = 0; j < 125; j++)
            {
                printf("NGF %d\n", temp_buf[j]);
            }
        }
    }

    return 0;
}

static const char *gpio_irq_str[] = {
    "LEVEL_LOW",  // 0x1
    "LEVEL_HIGH", // 0x2
    "EDGE_FALL",  // 0x4
    "EDGE_RISE"   // 0x8
};

void gpio_event_string(char *buf, uint32_t events)
{
    for (uint i = 0; i < 4; i++)
    {
        uint mask = (1 << i);
        if (events & mask)
        {
            // Copy this event string into the user string
            const char *event_str = gpio_irq_str[i];
            while (*event_str != '\0')
            {
                *buf++ = *event_str++;
            }
            events &= ~mask;

            // If more events add ", "
            if (events)
            {
                *buf++ = ',';
                *buf++ = ' ';
            }
        }
    }
    *buf++ = '\0';
}
